#ifndef _factory_h__
#define _factory_h__
#include <hash_map>
#include <util/smartptr.h>
#include <util/singleton.h>

namespace gecko
{

	// abstract base class for creator objects
	template<typename BaseType>
	class ICreator
	{
	public:
		virtual StrongPtr<BaseType> Create() = 0;
	};

	// concrete class for creator object
	template<typename BaseType, typename DerivedType>
	class Creator : public ICreator<BaseType>
	{
	public:
		StrongPtr<BaseType> Create()
		{
			return StrongPtr<BaseType>(new DerivedType);
		}
	};

	// templated object factory
	template<typename BaseType>
	class Factory : public Singleton<Factory<BaseType>>
	{
	public:
		// register a type based on a string
		template<typename DerivedType> void Register(const char* typeName)
		{
			m_creatorMap[typeName] = new Creator<BaseType, DerivedType>();
		}

		// create a type based on a string
		StrongPtr<BaseType> Create(const char* typeName)
		{
			return m_creatorMap[typeName]->Create();
		}

	private:
		// comparison for hash_map
		struct compare_str
		{
			bool operator()(const char* p1, const char*p2) const
			{
				return strcmp(p1,p2)!=0;
			}
		};

		// map of object class names to creator objects
		typedef std::hash_map< const char*, ICreator<BaseType>*, std::hash_compare<const char*, compare_str> > CreatorMap;
		CreatorMap m_creatorMap;
	};

	// an object designed to make registering classes a step easier (see macro below)
	template<typename Base, typename DerivedType>
	class FactoryRegister
	{
	public:
		FactoryRegister(const char* typeName)
		{
			Factory<Base>::Get().Register<DerivedType>(typeName);
		}
	};

}

// register a class with its factory - declare this globally in your class's .cpp file
#define REGISTER_WITH_FACTORY(BaseClass, DerivedClass) static gecko::FactoryRegister<BaseClass, DerivedClass> REGISTER_FOR_FACTORY_##DerivedClass(#DerivedClass)

#endif // #ifndef _factory_h__